package tt.dz.order.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @title 有贝支付工具类
 * @author zhoutian
 */
@Component
public class YouBeiPayUtil {
	private static Logger log = LoggerFactory.getLogger(YouBeiPayUtil.class);
	
	public static final String RET_SUCCESS_JSON = "{\"ret_code\":\"0000\",\"ret_msg\":\"交易成功\"}";
	
	public static final String RET_FAIL_JSON = "{\"ret_code\":\"fail\",\"ret_msg\":\"交易失败\"}";
	
	/** 商户的私钥 */
	public static final String PARTNER_PRIVATE_KEY  = "";
	
	/** 有贝的公钥 */
	public static final String YOUBEI_PUBLIC_KEY  = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG+OCv7dcCdchCohSJWzgYN+TJJC2INtQNeLdBDUV4+KuHnmpKhbOEEuHbPWW+ozEGcZY+ome1Ak+4/VUVMshDJYsGO2AEY7o9zXJ0rHKGyn4o/NQMNJWs70mwjHRDYm9+p2OCx4TFaZsikJS8hCPXHAEH2J5Lo8RO12KzetUHEwIDAQAB";
	
	/** 有贝先付退款接口地址 */
	private static final String YOUBEI_REFUND_URL = "https://m.uubee.com/uubee_api/refund.htm";
	
	public static final String INPUT_CHARSET = "utf-8";
	
	public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
	
	/** 数据传输超时时间 */
	private static int socketTimeout = 5 * 1000;
	
	/** 连接超时时间  */
	private static int connectionTimeout = 5 * 1000;
	
	/** 连接请求超时时间  */
	private static int connectionRequestTimeout = 5 * 1000;
	
	private static SSLConnectionSocketFactory sslsf;
	
	@PostConstruct
	public void init(){
        try {
        	KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        	keyStore.load(null, null);
        	SSLContext sslcontext = SSLContext.getInstance("TLS");
        	KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        	kmf.init(keyStore, null);
        	sslcontext.init(kmf.getKeyManagers(), new TrustManager[] { 
            		new X509TrustManager(){
						@Override
						public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
							
						}
						
						@Override
						public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
							
						}
		
						@Override
						public X509Certificate[] getAcceptedIssuers() {
							return null;
						}
					}
            }, null);
			// Allow TLSv1 protocol only
			sslsf = new SSLConnectionSocketFactory(
					sslcontext, 
					new String[] { "TLSv1" },
					null, 
					SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
			);
        } catch(Exception e){
        	log.error("有贝先付支付初始化加载KeyStore失败，" + e);
        }
	}
	
	/** 
     * 除去数组中的空值和签名参数
     * @param sArray 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {
        Map<String, String> result = new HashMap<String, String>();
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
                || key.equalsIgnoreCase("sign_type")) {
            	//值为空或者key为"sign"的参数不进行拼接
                continue;
            }
            result.put(key, value);
        }
        return result;
    }

    /** 
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        StringBuilder prestr = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (i == keys.size() - 1) {//拼接时，不包括最后一个&字符
                prestr = prestr.append(key).append("=").append(value);
            } else {
                prestr = prestr.append(key).append("=").append(value).append("&");
            }
        }
        return prestr.toString();
    }
	
	/**
	 * 有贝支付回调验证sign签名
	 * @param params
	 * @return true/false
	 * @throws NoSuchAlgorithmException 
	 * @throws UnsupportedEncodingException 
	 */
	public static boolean verify(Map<String, String> params) throws NoSuchAlgorithmException, UnsupportedEncodingException{
		String sign = (String) params.get("sign");
	    if(sign == null) {
	    	log.error("微信支付回调验证sign签名,签名为空");
	    	return false;
	    }
	    //过滤空值、sign与sign_type参数
    	Map<String, String> sParaNew = paraFilter(params);
    	//拼接字符串
        String preSignStr = createLinkString(sParaNew);        
        return doVerify(preSignStr, sign, YOUBEI_PUBLIC_KEY, INPUT_CHARSET);
	}
	
	/**
	* RSA验签名检查
	* @param content 待签名数据
	* @param sign 签名值
	* @param youbei_public_key 有贝公钥
	* @param input_charset 编码格式
	* @return 布尔值
	*/
	private static boolean doVerify(String content, String sign, String youbei_public_key, String input_charset){
		try {
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	        byte[] encodedKey = Base64.decode(youbei_public_key);
	        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));		
			java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);		
			signature.initVerify(pubKey);
			signature.update( content.getBytes(input_charset) );		
			return signature.verify( Base64.decode(sign) );		
		} catch(Exception e){
			log.error("有贝RSA验签名检查失败", e);
			return false;
		}
	}
	
	/**
	 * 有贝先付生成sign签名
	 * @return 签名字符串
	 */
	public static String sign(Map<String, String> params) throws UnsupportedEncodingException {
		//过滤空值、sign与sign_type参数
    	Map<String, String> sParaNew = paraFilter(params);
    	//拼接字符串
        String linkedStr = createLinkString(sParaNew);
        return doSign(linkedStr, PARTNER_PRIVATE_KEY, INPUT_CHARSET);
	}
	
	/**
	 * RSA签名
	 * @param content 待签名数据
	 * @param privateKey 商户私钥
	 * @param input_charset 编码格式
	 * @return 签名值
	 */
	private static String doSign(String content, String privateKey, String input_charset){
        try {
        	PKCS8EncodedKeySpec priPKCS8 	= new PKCS8EncodedKeySpec( Base64.decode(privateKey) ); 
        	KeyFactory keyf 				= KeyFactory.getInstance("RSA");
        	PrivateKey priKey 				= keyf.generatePrivate(priPKCS8);
            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            signature.update( content.getBytes(input_charset) );
            byte[] signed = signature.sign();            
            return Base64.encode(signed);
        } catch (Exception e) {
        	log.error("有贝RSA签名失败", e);
        }        
        return null;
    }
	
	/**
	 * 有贝先付退款发送https请求
	 * @param params
	 */
	public static String sendRefundRequest(String paramJsonStr) {
		StringBuilder retJsonStr = new StringBuilder();
		CloseableHttpClient httpclient = null;
		CloseableHttpResponse response = null;
		try {
			httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			HttpPost httpPost = new HttpPost(YOUBEI_REFUND_URL);
			//设置请求和传输超时时间httpGet.setConfig(requestConfig);
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(socketTimeout)
					.setConnectTimeout(connectionTimeout)
					.setConnectionRequestTimeout(connectionRequestTimeout)
					.build();
			httpPost.setConfig(requestConfig);
			StringEntity strEntity = new StringEntity(paramJsonStr, ContentType.create("application/json", INPUT_CHARSET));
			httpPost.setEntity(strEntity);
			response = httpclient.execute(httpPost);
			int responseStatus = response.getStatusLine().getStatusCode();
			if(responseStatus != HttpStatus.SC_OK){
				log.error("有贝先付退款发送https请求，响应状态不正确，responseStatus：" + responseStatus);
				return retJsonStr.toString();
			}
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				InputStreamReader isr = new InputStreamReader(entity.getContent(), INPUT_CHARSET);
				BufferedReader bufferedReader = new BufferedReader(isr);
				String text;
				while ((text = bufferedReader.readLine()) != null) {
					retJsonStr.append(text);
				}
				bufferedReader.close();
				isr.close();
			}
			EntityUtils.consume(entity);
		} catch (Exception e) {
			log.error("有贝先付退款发送https请求出错，" + e);
		} finally {
			try {
				if(response != null){
					response.close();
				}
				if(httpclient != null){
					httpclient.close();
				}
			} catch (IOException e) {
				log.error("有贝先付退款发送https请求,关闭httpclient出错" + e);
			}
		}
		return retJsonStr.toString();
	}
}